/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.osdtsystem.hierarchy.io;

import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import org.osdtsystem.hierarchy.Hierarchy;

/**
 * An abstract class that implements basic hierarchy manager methods.
 * @author Matthias Buch-Kromann
 */
abstract class AbstractHierarchyManager implements HierarchyManager {
    Map<String, Hierarchy<?>> hierarchies = new HashMap<String, Hierarchy<?>>();
    Map<Hierarchy<?>, String> hierarchyNames = new HashMap<Hierarchy<?>, String>();
    Map<String, HierarchyIO> readers = new HashMap<String, HierarchyIO>();
    Map<String, HierarchyIO> writers = new HashMap<String, HierarchyIO>();
    Map<String, String> encodings = new HashMap<String, String>();
    Map<String, URL> urls = new HashMap<String, URL>();

    AbstractHierarchyManager() {
    }

    abstract Reader urlReader(URL url);
    abstract Writer urlWriter(URL url);


    @Override
    public void addHierarchy(Hierarchy<?> hierarchy, String hierarchyName, String encodingFormat, URL url) {
        // Check that hierarchy name hasn't been taken already
        if (hierarchies.containsKey(hierarchyName))
                throw new IllegalArgumentException("Hierarchy with name "
                + hierarchyName + " already exists in hierarchy manager "
                + this);

        // Store hierarchy
        hierarchies.put(hierarchyName, hierarchy);
        hierarchyNames.put(hierarchy, hierarchyName);
        encodings.put(hierarchyName, encodingFormat);
        urls.put(hierarchyName, url);
    }

    @Override
    public void setReader(String encodingFormat, HierarchyIO hierarchyReader) {
        readers.put(encodingFormat, hierarchyReader);
    }

    @Override
    public void addWriter(String encodingFormat, HierarchyIO hierarchyWriter) {
        writers.put(encodingFormat, hierarchyWriter);
    }

    @Override
    public void removeHierarchy(String hierarchyName) {
        Hierarchy<?> hierarchy = hierarchies.get(hierarchyName);
        if (hierarchy != null)
            hierarchyNames.remove(hierarchy);
        hierarchies.remove(hierarchyName);
        encodings.remove(hierarchyName);
        urls.remove(hierarchyName);
    }

    @Override
    public void setHierarchyLocation(String hierarchyName, String encodingFormat, URL url) {
        urls.put(hierarchyName, url);
        encodings.put(hierarchyName, encodingFormat);
    }

    @Override
    public Hierarchy<?> loadHierarchy(String hierarchyName) throws IOException {
        // Check hierarchy name and existence in hierarchy manager
        if (hierarchyName == null || ! hierarchies.containsKey(hierarchyName))
            throw new IllegalArgumentException("Non-existent hierarchy name " 
                    + (hierarchyName == null ? "_null_" : hierarchyName));
        
        // Check encoding
        String encoding = encodings.get(hierarchyName);
        HierarchyIO hierarchyReader = readers.get(encoding);
        if (hierarchyReader == null)
            throw new IllegalArgumentException("Cannot find reader for encoding "
                    + encoding + " when loading hierarchy named " + hierarchyName);

        // Open URL
        URL url = urls.get(hierarchyName);
        Reader urlReader = urlReader(url);
        if (urlReader == null)
            throw new IllegalArgumentException("Cannot find url for hierarchy" +
                    "named " + hierarchyName);

        // Load hierarchy
        return hierarchyReader.read(this, urlReader);
    }

    @Override
    public void saveHierarchy(String hierarchyName) throws IOException {
        // Check hierarchy name and existence in hierarchy manager
        Hierarchy<?> hierarchy = hierarchies.get(hierarchyName);
        if (hierarchyName == null || hierarchy == null)
            throw new IllegalArgumentException("Non-existent hierarchy name "
                    + (hierarchyName == null ? "_null_" : hierarchyName));

        // Check encoding
        String encoding = encodings.get(hierarchyName);
        HierarchyIO hierarchyWriter = writers.get(encoding);
        if (hierarchyWriter == null)
            throw new IllegalArgumentException("Cannot find writer for encoding "
                    + encoding + " when saving hierarchy named " + hierarchyName);

        // Open URL
        URL url = urls.get(hierarchyName);
        Writer urlWriter = urlWriter(url);
        if (urlWriter == null)
            throw new IllegalArgumentException("Cannot find url writer for hierarchy" +
                    "named " + hierarchyName);

        // Load hierarchy
        hierarchyWriter.write(this, hierarchy, urlWriter);
    }
}
